package org.anq.ddm.service;

import org.anq.ddm.pojo.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;

@Service
public class CamundaService {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${app.rest.path}")
    private String restPath;

    /**
     * 获取启动实例前的初始表单
     * @return
     */
    public String getStartFormKey(String definationKey){
        String url = restPath+"process-definition/key/"+definationKey+"/startForm";
        HashMap o = (HashMap)restTemplate.getForObject(url,Object.class);
        if(o!=null){
            return o.get("key").toString();
        }
        return null;
    }

    /**
     * 根据taskId获取当前Task的formkey
     * @param taskId
     * @return
     */
    public String getFormKey(String taskId){
        String url = restPath+"task/"+taskId+"/form";
        HashMap o = (HashMap)restTemplate.getForObject(url,Object.class);
        if(o!=null){
            return o.get("key").toString();
        }
        return null;
    }

    /**
     * 生成流程实例
     * 根据部署的流程key生成流程的实例（一个申请对应一个实例）
     */
    public String startInstance(String definationKey,Map<String,Object> param){

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<HashMap<String, Object>> request = new HttpEntity<>(null, headers);//null为map格式的参数

        String url = restPath+"process-definition/key/"+definationKey+"/start";
        HashMap o = (HashMap)restTemplate.postForObject(url,request,Object.class);

        // 部署的流程实例id,该id需要保存至申请单中作为app与流程引擎联系的唯一标识
        String id= o.get("id").toString();

        //设置instance级别的参数
        if(param!=null) {
            Iterator<String> it = param.keySet().iterator();
            while (it.hasNext()) {
                String key = it.next();
                String value = param.get(key).toString();
                String globalPath = restPath + "process-instance/" + id + "/variables/" + key;
                Map<String, String> p = new HashMap<>();
                p.put("value", value);
                restTemplate.put(globalPath, p);//无返回值
            }
        }
        return id;
    }


    /**
     * 根据instanceId查询当前instance进行到哪一个task了。
     * @param instanceId
     * @return instance的状态,返回list是考虑可能有【并行】任务，但后勤APP中应该没有。如果List为空（非null）则说明instance已完成，没有任务了。
     */
    public List<String> queryTaskStatusByInstanceId(String instanceId){
        String url = restPath+"task?processInstanceId="+instanceId;
        List<Object> list = restTemplate.getForObject(url,List.class);
        List<String> returnList = null;
        if(list!=null){
            returnList = new ArrayList<>();
            for(Object o : list){
                Map m = (HashMap)o;
                returnList.add(m.get("name").toString());
            }
        }
        return returnList;
    }

    /**
     * 根据instanceId查询当前taskId。
     * @param instanceId
     * @return 返回当前实例当前任务的taskId
     */
    public List<String> queryTaskIdByInstanceId(String instanceId){
        String url = restPath + "task?processInstanceId=" + instanceId;
        List<Object> list = restTemplate.getForObject(url, List.class);
        List<String> returnList = null;
        if(list != null){
            returnList = new ArrayList<>();
            for(Object o : list){
                Map m = (HashMap)o;
                returnList.add(m.get("id").toString());
            }
        }

        return returnList;
    }

    /**
     * 根据角色查询待办
     * @param role （必须）用户角色
     * @param params (可选)格式为 key-operator-value,如departmentId_eq_3为，departmentId=3,只支持instancec级别的变量
     * @return List<Task> 获取当前role的任务列表
     */
    public List<Task> queryTask(String definationKey,String role, String params){
        if (role != null) {
            String url2 = restPath + "task?assigneeLike=%_" + role + "_%&processDefinitionKey=" + definationKey + "&sortBy=created&sortOrder=asc";
            if (params != null) {
                url2 += "&processVariables=" + params;
            }
            List<Object> list = restTemplate.getForObject(url2, List.class);
            if (list != null) {
                List<Task> list1 = new ArrayList<>();
                for (Object o : list) {
                    Map m = (Map)o;
                    Task t = new Task();
                    t.setName(m.get("name").toString());
                    t.setStartTime(m.get("created").toString());
                    t.setId(m.get("id").toString());
                    t.setInstanceId(m.get("processInstanceId").toString());
                    list1.add(t);
                }
                return list1;
            }
        }

        return null;
    }

    /**
     * 查询所有待办
     * @return List<Task> 获取所有任务列表
     */
    public List<Task> queryAllTask(String definationKey){
            String url2 = restPath + "task?processDefinitionKey=" + definationKey + "&sortBy=created&sortOrder=asc";
            List<Object> list = restTemplate.getForObject(url2, List.class);
            if (list != null) {
                List<Task> list1 = new ArrayList<>();
                for (Object o : list) {
                    Map m = (Map)o;
                    Task t = new Task();
                    t.setName(m.get("name").toString());
                    t.setStartTime(m.get("created").toString());
                    t.setId(m.get("id").toString());
                    t.setInstanceId(m.get("processInstanceId").toString());
                    list1.add(t);
                }
                return list1;
        }

        return null;
    }

    /**
     * 完成任务
     * @param taskId 申请流程当前的任务id，前台会现实当前用户执行到流程中的哪个任务，用户点击执行这个任务的操作会传回任务id
     * @param assignee 执行操作的用户uid
     * @param localParams 只在该任务范围内起作用的变量，如审批不通过原因、修改原因、备注等。
     * @param globalParams 在流程全局范围内起作用的变量，后续赋值覆盖前一个。如电子设备和办公用品类型id、流程网关会根据此id执行不同流程。
     *                     因需要在任务之间传递，因此设置为globalParams
     * @return -1:完成失败  0:完成成功   1：完成成功，instance已结束
     */
    public int completeTask(String instanceId,String taskId,String assignee, Map<String,Object> localParams, Map<String,Object> globalParams){

        try {
            /**
             * 设置执行人（assignee）
             */
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            Map<String, String> user = new HashMap<>();
            user.put("userId", assignee);
            HttpEntity<Map<String, String>> assigneeRequest = new HttpEntity<>(user, headers);

            String url = restPath + "task/" + taskId + "/assignee";
            restTemplate.postForObject(url, assigneeRequest, Object.class);//无返回值

            /**
             * 设置变量（task范围）
             */
            if(localParams!=null) {
                Iterator<String> it = localParams.keySet().iterator();
                while (it.hasNext()) {
                    String key = it.next();
                    String value = localParams.get(key).toString();
                    String localPath = restPath + "task/" + taskId + "/localVariables/" + key;
                    Map<String, String> lp = new HashMap<>();
                    lp.put("value", value);
                    restTemplate.put(localPath, lp);//无返回值
                }
            }

            /**
             * 设置变量（全局范围，用于跨task跳转。
             * 建议在不通过的时候，编写不通过原因，同时设置task范围和全局范围变量，
             * task范围变量用于记录，全局范围变量用户传递给下一个task查看，该变量会被覆盖）
             */
            if(globalParams!=null) {
                Iterator<String> it2 = globalParams.keySet().iterator();
                while (it2.hasNext()) {
                    String key = it2.next();
                    String value = globalParams.get(key).toString();
                    String globalPath = restPath + "task/" + taskId + "/variables/" + key;
                    Map<String, String> gp = new HashMap<>();
                    gp.put("value", value);
                    restTemplate.put(globalPath, gp);//无返回值
                }
            }

            /**
             * 完成任务
             */
            HttpEntity<Map<String, String>> completeRequest = new HttpEntity<>(null, headers);
            String url3 = restPath + "task/" + taskId + "/complete";
            restTemplate.postForObject(url3, completeRequest, Object.class);//无返回值

            List<String> list =this.queryTaskStatusByInstanceId(instanceId);

            if(list!=null&&list.size()<1){
                return 1;
            }else{
                return 0;
            }
        }catch (Exception ex){
            return -1;
        }
    }


    /**
     * 根据instanceid完成当前任务（一般用于创建instance后的第一个任务）
     * @param instanceId 申请流程当前的任务id，前台会现实当前用户执行到流程中的哪个任务，用户点击执行这个任务的操作会传回任务id
     * @param assignee 执行操作的用户uid
     * @param localParams 只在该任务范围内起作用的变量，如审批不通过原因、修改原因、备注等。
     * @param globalParams 在流程全局范围内起作用的变量，后续赋值覆盖前一个。如电子设备和办公用品类型id、流程网关会根据此id执行不同流程。
     *                     因需要在任务之间传递，因此设置为globalParams
     * @return -1:完成失败  0:完成成功   1：完成成功，instance已结束
     */
    public int completeInstance(String instanceId,  String assignee, Map<String,Object> localParams, Map<String,Object> globalParams){

        try {
            String url = restPath+"task?processInstanceId="+instanceId;
            List<Object> list = restTemplate.getForObject(url,List.class);

            int flag = 0;
            if(list!=null){
                for(Object o:list){
                    Map m = (HashMap)o;
                    String taskId = m.get("id").toString();
                    //调用完成单个task
                    flag = this.completeTask(instanceId,taskId,assignee,localParams,globalParams);
                }
            }
            return flag;
        }catch (Exception ex){
            return -1;
        }
    }

    /**
     * 根据instanceId删除instance
     * @param instanceId
     * @return
     */
    public Boolean deleteInstance(String instanceId){

        try {
            String url = restPath + "process-instance/" + instanceId;
            restTemplate.delete(url);
            return true;
        }catch (Exception ex){
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * 查询instance所经历的任务
     * 当list的第一个task的endTime为null时，说明流程未结束，从list的第二个任务开始asc排序。
     * 当list的第一个task的endTime不为null时，说明流程已结束。整个list按照asc排序。
     * @param instanceId
     * @return 历史任务列表
     */
    public List<Task> historyTask(String instanceId){
        String url = restPath+"history/task?processInstanceId="+instanceId+"&sortBy=endTime&sortOrder=asc";
        List<Object> list = restTemplate.getForObject(url,List.class);
        List<Task> taskList = null;
        if(list!=null){
            taskList = new ArrayList<>();

            for(Object o : list){
                Map m = (HashMap)o;

                Task t = new Task();
                t.setId(m.get("id").toString());
                t.setInstanceId(instanceId);
                t.setName(m.get("name").toString());
                t.setStartTime(m.get("startTime").toString());
                if(m.get("endTime")!=null&&m.get("endTime")!=""){
                    t.setAssignee(m.get("assignee").toString());
                    t.setEndTime(m.get("endTime").toString());

                    String paramUrl = restPath+"history/variable-instance?taskIdIn="+t.getId();
                    List<Object> params = restTemplate.getForObject(paramUrl,List.class);

                    if(params!=null){
                        Map<String,String> localParams=new HashMap<>();
                        for(Object oo :params){
                            Map mm = (HashMap)oo;
                            localParams.put(mm.get("name").toString(),mm.get("value").toString());
                        }
                        t.setLocalParams(localParams);
                    }
                }
                taskList.add(t);
            }
        }
        return taskList;
    }

}
